<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <title>MVVM框架——CommunityToolkit.Mvvm - 陈的错题集</title><meta name="Description" content="陈的错题集 - 个人笔记"><meta property="og:title" content="MVVM框架——CommunityToolkit.Mvvm" />
<meta property="og:description" content="模型-视图-视图模型 (MVVM) 是用于解耦 UI 代码和非 UI 代码的 UI 体系结构设计模式。 借助 MVVM，可以在 XAML 中以声明方式定义 UI，并使用数据绑定标记将 UI 链接" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://example.com/wpf_communitytoolkitmvvm/" /><meta property="og:image" content="https://example.com/logo.png"/><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2024-03-28T10:17:19+08:00" />
<meta property="article:modified_time" content="2024-03-28T10:17:19+08:00" /><meta property="og:site_name" content="陈的错题集" />
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://example.com/logo.png"/>

<meta name="twitter:title" content="MVVM框架——CommunityToolkit.Mvvm"/>
<meta name="twitter:description" content="模型-视图-视图模型 (MVVM) 是用于解耦 UI 代码和非 UI 代码的 UI 体系结构设计模式。 借助 MVVM，可以在 XAML 中以声明方式定义 UI，并使用数据绑定标记将 UI 链接"/>
<meta name="application-name" content="陈的错题集">
<meta name="apple-mobile-web-app-title" content="陈的错题集"><meta name="theme-color" content="#ffffff"><meta name="msapplication-TileColor" content="#da532c"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"><link rel="manifest" href="/site.webmanifest"><link rel="canonical" href="https://example.com/wpf_communitytoolkitmvvm/" /><link rel="prev" href="https://example.com/cia402_07ptpfunctionblock/" /><link rel="stylesheet" href="/css/style.min.css"><link rel="preload" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.1/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
        <noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.1/css/all.min.css"></noscript><link rel="preload" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.1/animate.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
        <noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.1/animate.min.css"></noscript><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "MVVM框架——CommunityToolkit.Mvvm",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/example.com\/wpf_communitytoolkitmvvm\/"
        },"image": ["https:\/\/example.com\/images\/Apple-Devices-Preview.png"],"genre": "posts","keywords": "Mvvm, WPF","wordcount":  3534 ,
        "url": "https:\/\/example.com\/wpf_communitytoolkitmvvm\/","datePublished": "2024-03-28T10:17:19+08:00","dateModified": "2024-03-28T10:17:19+08:00","publisher": {
            "@type": "Organization",
            "name": "xxxx","logo": "https:\/\/example.com\/images\/avatar.png"},"author": {
                "@type": "Person",
                "name": "Jacob Chen"
            },"description": ""
    }
    </script></head>
    <body data-header-desktop="fixed" data-header-mobile="auto"><script type="text/javascript">(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('auto' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : 'auto' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><header class="desktop" id="header-desktop">
    <div class="header-wrapper">
        <div class="header-title">
            <a href="/" title="陈的错题集">💻陈的错题集</a>
        </div>
        <div class="menu">
            <div class="menu-inner"><a class="menu-item" href="/posts/"> 📜归档 </a><a class="menu-item" href="/tags/"> 🏷️标签 </a><a class="menu-item" href="/categories/"> 📂分类 </a><a class="menu-item" href="/about/"> ⭐关于 </a><span class="menu-item delimiter"></span><span class="menu-item search" id="search-desktop">
                        <input type="text" placeholder=" " id="search-input-desktop">
                        <a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-desktop" title="搜索">
                            <i class="fas fa-search fa-fw" aria-hidden="true"></i>
                        </a>
                        <a href="javascript:void(0);" class="search-button search-clear" id="search-clear-desktop" title="清空">
                            <i class="fas fa-times-circle fa-fw" aria-hidden="true"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-desktop">
                            <i class="fas fa-spinner fa-fw fa-spin" aria-hidden="true"></i>
                        </span>
                    </span><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw" aria-hidden="true"></i>
                </a></div>
        </div>
    </div>
</header><header class="mobile" id="header-mobile">
    <div class="header-container">
        <div class="header-wrapper">
            <div class="header-title">
                <a href="/" title="陈的错题集">💻陈的错题集</a>
            </div>
            <div class="menu-toggle" id="menu-toggle-mobile">
                <span></span><span></span><span></span>
            </div>
        </div>
        <div class="menu" id="menu-mobile"><div class="search-wrapper">
                    <div class="search mobile" id="search-mobile">
                        <input type="text" placeholder=" " id="search-input-mobile">
                        <a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-mobile" title="搜索">
                            <i class="fas fa-search fa-fw" aria-hidden="true"></i>
                        </a>
                        <a href="javascript:void(0);" class="search-button search-clear" id="search-clear-mobile" title="清空">
                            <i class="fas fa-times-circle fa-fw" aria-hidden="true"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-mobile">
                            <i class="fas fa-spinner fa-fw fa-spin" aria-hidden="true"></i>
                        </span>
                    </div>
                    <a href="javascript:void(0);" class="search-cancel" id="search-cancel-mobile">
                        取消
                    </a>
                </div><a class="menu-item" href="/posts/" title="">📜归档</a><a class="menu-item" href="/tags/" title="">🏷️标签</a><a class="menu-item" href="/categories/" title="">📂分类</a><a class="menu-item" href="/about/" title="">⭐关于</a><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                <i class="fas fa-adjust fa-fw" aria-hidden="true"></i>
            </a></div>
    </div>
</header><div class="search-dropdown desktop">
        <div id="search-dropdown-desktop"></div>
    </div>
    <div class="search-dropdown mobile">
        <div id="search-dropdown-mobile"></div>
    </div><main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">目录</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single"><h1 class="single-title animate__animated animate__flipInX">MVVM框架——CommunityToolkit.Mvvm</h1><div class="post-meta">
            <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel="author" class="author"><i class="fas fa-user-circle fa-fw" aria-hidden="true"></i>Jacob Chen</a></span>&nbsp;<span class="post-category">收录于 <a href="/categories/csharp/"><i class="far fa-folder fa-fw" aria-hidden="true"></i>CSharp</a></span></div>
            <div class="post-meta-line"><i class="far fa-calendar-alt fa-fw" aria-hidden="true"></i>&nbsp;<time datetime="2024-03-28">2024-03-28</time>&nbsp;<i class="fas fa-pencil-alt fa-fw" aria-hidden="true"></i>&nbsp;约 3534 字&nbsp;
                <i class="far fa-clock fa-fw" aria-hidden="true"></i>&nbsp;预计阅读 8 分钟&nbsp;</div>
        </div><div class="details toc" id="toc-static"  data-kept="">
                <div class="details-summary toc-title">
                    <span>目录</span>
                    <span><i class="details-icon fas fa-angle-right" aria-hidden="true"></i></span>
                </div>
                <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#常见-mvvvm-框架">常见 MVVVM 框架</a></li>
    <li><a href="#communitytoolkitmvvm"><strong>CommunityToolkit.Mvvm</strong></a>
      <ul>
        <li><a href="#安装">安装</a></li>
        <li><a href="#功能">功能</a></li>
      </ul>
    </li>
    <li><a href="#observableobject可观测对象">ObservableObject（可观测对象）</a>
      <ul>
        <li><a href="#可通知属性的创建">可通知属性的创建</a>
          <ul>
            <li><a href="#运行案例">运行案例</a></li>
            <li><a href="#xaml界面代码">XAML界面代码</a></li>
            <li><a href="#界面后台代码">界面后台代码</a></li>
            <li><a href="#viewmodel代码">ViewModel代码</a></li>
            <li><a href="#自动生成的代码">自动生成的代码</a></li>
          </ul>
        </li>
        <li><a href="#分部方法的使用">分部方法的使用</a></li>
      </ul>
    </li>
    <li><a href="#relaycommand命令">RelayCommand（命令）</a>
      <ul>
        <li><a href="#不带参数的命令">不带参数的命令</a>
          <ul>
            <li><a href="#运行案例-1">运行案例</a></li>
            <li><a href="#xaml界面代码-1">XAML界面代码</a></li>
            <li><a href="#界面后台代码-1">界面后台代码</a></li>
            <li><a href="#viewmodel代码-1">ViewModel代码</a></li>
            <li><a href="#自动生成的代码-1">自动生成的代码</a></li>
          </ul>
        </li>
        <li><a href="#带参数的命令">带参数的命令</a>
          <ul>
            <li><a href="#运行案例-2">运行案例</a></li>
            <li><a href="#xaml界面代码-2">XAML界面代码</a></li>
            <li><a href="#界面后台代码-2">界面后台代码</a></li>
            <li><a href="#viewmodel代码-2">ViewModel代码</a></li>
            <li><a href="#自动生成的代码-2">自动生成的代码</a></li>
          </ul>
        </li>
      </ul>
    </li>
    <li><a href="#messager信使">Messager（信使）</a>
      <ul>
        <li><a href="#使用流程及工作模式">使用流程及工作模式</a></li>
        <li><a href="#weakreferencemessager">WeakReferenceMessager</a>
          <ul>
            <li><a href="#运行案例-3">运行案例</a></li>
            <li><a href="#xaml界面代码-3">XAML界面代码</a></li>
            <li><a href="#界面后台代码-3">界面后台代码</a></li>
            <li><a href="#新建消息类">新建消息类</a></li>
            <li><a href="#viewmodel代码-3">ViewModel代码</a></li>
          </ul>
        </li>
      </ul>
    </li>
    <li><a href="#参考资料">参考资料</a></li>
  </ul>
</nav></div>
            </div><div class="content" id="content"><!-- # MVVM框架——CommunityToolkit.Mvvm -->
<blockquote>
<p>模型-视图-视图模型 (MVVM) 是用于解耦 UI 代码和非 UI 代码的 UI 体系结构设计模式。 借助 MVVM，可以在 XAML 中以声明方式定义 UI，并使用数据绑定标记将 UI 链接到包含数据和命令的其他层。</p>
</blockquote>
<p>MVVM 是 WPF 开发中最常见的一种设计模式，但是为了实现UI界面与数据的分离。开发者往往需要编写很多额外的代码来实现MVVM。所以使用框架可以大大减少代码的编写量。</p>
<h2 id="常见-mvvvm-框架">常见 MVVVM 框架</h2>
<p>常见的MVVM框架中，有<strong>Prism</strong>（之前一直在用，但是现在更新了授权协议，商用有风险，所以也就不用了）、<strong>MVVM Light</strong>（已经停更）、<strong>MVVM Toolkit</strong>等。</p>
<h2 id="communitytoolkitmvvm"><strong>CommunityToolkit.Mvvm</strong></h2>
<p><strong>CommunityToolkit.Mvvm</strong> 又名 <strong>MVVM Toolkit</strong>。它是由微软Windows Community Toolkit 开发的一个现代化、快速以及模块化的 MVVM 库。而且 MVVM Toolkit 延续了 MVVM Light 的风格，是一个轻量级、高性能的组件。</p>
<p>从 8.0.0 版本开始，MVVM Toolkit 提供了一个 MVVM Toolkit source generators 增量生成器，用于自动生成 MVVM 代码，大大减小了开发者的负担。（要求VS 2022版本）</p>
<h3 id="安装">安装</h3>
<p>通过 NuGet 安装
<img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%ae%89%e8%a3%85.png"
        data-srcset="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%ae%89%e8%a3%85.png, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%ae%89%e8%a3%85.png 1.5x, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%ae%89%e8%a3%85.png 2x"
        data-sizes="auto"
        alt="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM框架-安装.png"
        title="CommunityToolkit.Mvvm安装" /></p>
<h3 id="功能">功能</h3>
<p>CommunityToolkit.Mvvm 框架按照功能可以大致分为3类：ObservableObject（可观测对象）、RelayCommand（命令）、Messager（信使）。</p>
<h2 id="observableobject可观测对象">ObservableObject（可观测对象）</h2>
<p>ObservableObject 类实现了 INotifyPropertyChanged 和 INotifyPropertyChanging 接口，使之可以成为需要用于绑定属性变量通知的基类。</p>
<h3 id="可通知属性的创建">可通知属性的创建</h3>
<h4 id="运行案例">运行案例</h4>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-ObservableObject.png"
        data-srcset="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-ObservableObject.png, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-ObservableObject.png 1.5x, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-ObservableObject.png 2x"
        data-sizes="auto"
        alt="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM框架-ObservableObject.png"
        title="ObservableObject案例" /></p>
<h4 id="xaml界面代码">XAML界面代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="c">&lt;!--前台界面代码 MainWindow.xaml--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Window</span>
</span></span><span class="line"><span class="cl">    <span class="na">x:Class=</span><span class="s">&#34;MvvmToolkitExample.MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:x=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:d=</span><span class="s">&#34;http://schemas.microsoft.com/expression/blend/2008&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:local=</span><span class="s">&#34;clr-namespace:MvvmToolkitExample&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:mc=</span><span class="s">&#34;http://schemas.openxmlformats.org/markup-compatibility/2006&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Title=</span><span class="s">&#34;MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Width=</span><span class="s">&#34;800&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Height=</span><span class="s">&#34;450&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">mc:Ignorable=</span><span class="s">&#34;d&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Grid&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;TextBlock</span>
</span></span><span class="line"><span class="cl">            <span class="na">HorizontalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">VerticalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;32&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Text=</span><span class="s">&#34;{Binding Content}&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Grid&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Window&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>将 TextBlock 控件的Text属性绑定在 Content 属性上，当 Conent 属性出现变化时，界面也会一起更新。</p>
<h4 id="界面后台代码">界面后台代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="c1">//后台代码 MainWindow.xaml.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MainWindow</span> <span class="p">:</span> <span class="n">Window</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="n">MainWindow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">InitializeComponent</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="n">DataContext</span> <span class="p">=</span> <span class="k">new</span> <span class="n">MainWindowViewModel</span><span class="p">();</span>   <span class="c1">//指定用于数据绑定的类</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="viewmodel代码">ViewModel代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="c1">//ViewModel代码 MainWindowViewModel.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MainWindowViewModel</span> <span class="p">:</span> <span class="n">ObservableObject</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="na">    [ObservableProperty]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">string</span> <span class="n">content</span> <span class="p">=</span> <span class="s">&#34;通过MVVM方式，将字符串属性绑定到控件内容上&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ol>
<li>类继承于 ObservableObject，并设置为 partial 分部类。</li>
<li>声明 string 字段 content（可以是 content、_content 或者 m_content），生成器会自动生成 名称为 <strong>Content</strong> 的 string 属性。</li>
<li>字段添加特性 [ObservableProperty]，用于告诉编译器，该字段需要自动生成属性。</li>
</ol>
<h4 id="自动生成的代码">自动生成的代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="k">public</span> <span class="kt">string</span> <span class="n">Content</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">get</span> <span class="p">=&gt;</span> <span class="n">content</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">set</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(!</span><span class="n">EqualityComparer</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;.</span><span class="n">Default</span><span class="p">.</span><span class="n">Equals</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">value</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">OnContentChanging</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>   <span class="c1">//自动扩展的分部方法</span>
</span></span><span class="line"><span class="cl">            <span class="n">OnContentChanging</span><span class="p">(</span><span class="k">default</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="c1">//自动扩展的分部方法</span>
</span></span><span class="line"><span class="cl">            <span class="n">OnPropertyChanging</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="n">content</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">OnContentChanged</span><span class="p">(</span><span class="k">value</span><span class="p">);</span> <span class="c1">//自动扩展的分部方法</span>
</span></span><span class="line"><span class="cl">            <span class="n">OnContentChanged</span><span class="p">(</span><span class="k">default</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="c1">//自动扩展的分部方法</span>
</span></span><span class="line"><span class="cl">            <span class="n">OnPropertyChanged</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">//自动扩展的分部方法</span>
</span></span><span class="line"><span class="cl"><span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanging</span><span class="p">(</span><span class="kt">string</span> <span class="k">value</span><span class="p">);</span>   <span class="c1">//当 Content 属性修改中</span>
</span></span><span class="line"><span class="cl"><span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanging</span><span class="p">(</span><span class="kt">string?</span> <span class="n">oldValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">newValue</span><span class="p">);</span><span class="c1">//当 Content 属性修改中</span>
</span></span><span class="line"><span class="cl"><span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanged</span><span class="p">(</span><span class="kt">string</span> <span class="k">value</span><span class="p">);</span><span class="c1">//当 Content 属性修改后</span>
</span></span><span class="line"><span class="cl"><span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanged</span><span class="p">(</span><span class="kt">string?</span> <span class="n">oldValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">newValue</span><span class="p">);</span><span class="c1">//当 Content 属性修改后</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="分部方法的使用">分部方法的使用</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="c1">//ViewModel代码 MainWindowViewModel.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MainWindowViewModel</span> <span class="p">:</span> <span class="n">ObservableObject</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="na">    [ObservableProperty]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">string</span> <span class="n">content</span> <span class="p">=</span> <span class="s">&#34;通过MVVM方式，将字符串属性绑定到控件内容上&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">//当 Content 属性被修改时（赋值前），会调用该方法。</span>
</span></span><span class="line"><span class="cl">    <span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanging</span><span class="p">(</span><span class="kt">string?</span> <span class="n">oldValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">newValue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">throw</span> <span class="k">new</span> <span class="n">NotImplementedException</span><span class="p">();</span> 
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">//当 Content 属性被修改后（赋值后），会调用该方法。</span>
</span></span><span class="line"><span class="cl">    <span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanged</span><span class="p">(</span><span class="kt">string?</span> <span class="n">oldValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">newValue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">throw</span> <span class="k">new</span> <span class="n">NotImplementedException</span><span class="p">();</span> 
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="relaycommand命令">RelayCommand（命令）</h2>
<p>RelayCommand 类是 ICommand 实现，该实现可向 UI 界面（XAML）中公开方法或委托。可以让 UI 界面上如按钮之类具有命令属性的控件进行绑定。</p>
<h3 id="不带参数的命令">不带参数的命令</h3>
<h4 id="运行案例-1">运行案例</h4>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-RelayCommand.gif"
        data-srcset="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-RelayCommand.gif, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-RelayCommand.gif 1.5x, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-RelayCommand.gif 2x"
        data-sizes="auto"
        alt="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM框架-RelayCommand.gif"
        title="RelayCommand案例" /></p>
<h4 id="xaml界面代码-1">XAML界面代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="c">&lt;!--前台界面代码 MainWindow.xaml--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Window</span>
</span></span><span class="line"><span class="cl">    <span class="na">x:Class=</span><span class="s">&#34;MvvmToolkitExample.MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:x=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:d=</span><span class="s">&#34;http://schemas.microsoft.com/expression/blend/2008&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:local=</span><span class="s">&#34;clr-namespace:MvvmToolkitExample&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:mc=</span><span class="s">&#34;http://schemas.openxmlformats.org/markup-compatibility/2006&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Title=</span><span class="s">&#34;MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Width=</span><span class="s">&#34;800&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Height=</span><span class="s">&#34;450&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">mc:Ignorable=</span><span class="s">&#34;d&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Grid&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;Grid.RowDefinitions&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="na">Height=</span><span class="s">&#34;auto&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/Grid.RowDefinitions&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;TextBlock</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;0&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">HorizontalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">VerticalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;32&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Text=</span><span class="s">&#34;{Binding Content}&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;Button</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Margin=</span><span class="s">&#34;10&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Padding=</span><span class="s">&#34;20&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">HorizontalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">VerticalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Content=</span><span class="s">&#34;示例命令绑定&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Command=</span><span class="s">&#34;{Binding ChangeContentCommand}&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;20&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Grid&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Window&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>将 Button 控件的 Command 命令绑定在 ChangeContentCommand 上，当 Button 按钮按下时，会自动调用命令对应的方法 ChangeContent()。</p>
<h4 id="界面后台代码-1">界面后台代码</h4>
<p>与 ObservableObject（可观测对象）- 界面后台代码 一致。</p>
<h4 id="viewmodel代码-1">ViewModel代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="c1">//ViewModel代码 MainWindowViewModel.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MainWindowViewModel</span> <span class="p">:</span> <span class="n">ObservableObject</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">int</span> <span class="n">times</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">    [ObservableProperty]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">string</span> <span class="n">content</span> <span class="p">=</span> <span class="s">&#34;通过MVVM方式，将字符串属性绑定到控件内容上&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">//当 Content 属性被修改后（赋值后），会调用该方法。</span>
</span></span><span class="line"><span class="cl">    <span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanged</span><span class="p">(</span><span class="kt">string?</span> <span class="n">oldValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">newValue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">times</span><span class="p">++;</span>
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="p">=</span> <span class="s">$&#34;{newValue} : { times }&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">    [RelayCommand]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">void</span> <span class="n">ChangeContent</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Content</span> <span class="p">=</span> <span class="s">&#34;Content 已通过命令方式修改&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ol>
<li>声明无返回值 viod 的私有 private 方法 ChangeContent()。</li>
<li>生成器将使用方法名称并在末尾追加 “<strong>Command</strong>”，并且去除 “<strong>On</strong>” 前缀（如果存在）。</li>
<li>方法添加特性 [RelayCommand]，用于告诉编译器自动生成命令。</li>
</ol>
<h4 id="自动生成的代码-1">自动生成的代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="k">private</span> <span class="n">RelayCommand</span><span class="p">?</span> <span class="n">changeContentCommand</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="n">IRelayCommand</span> <span class="n">ChangeContentCommand</span> <span class="p">=&gt;</span> <span class="n">changeContentCommand</span> <span class="p">??=</span> <span class="k">new</span> <span class="n">RelayCommand</span><span class="p">(</span><span class="n">ChangeContent</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="带参数的命令">带参数的命令</h3>
<h4 id="运行案例-2">运行案例</h4>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%b8%a6%e5%8f%82RelayCommand.gif"
        data-srcset="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%b8%a6%e5%8f%82RelayCommand.gif, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%b8%a6%e5%8f%82RelayCommand.gif 1.5x, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-%e5%b8%a6%e5%8f%82RelayCommand.gif 2x"
        data-sizes="auto"
        alt="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM框架-带参RelayCommand.gif"
        title="带参RelayCommand案例" /></p>
<h4 id="xaml界面代码-2">XAML界面代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="c">&lt;!--前台界面代码 MainWindow.xaml--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Window</span>
</span></span><span class="line"><span class="cl">    <span class="na">x:Class=</span><span class="s">&#34;MvvmToolkitExample.MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:x=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:d=</span><span class="s">&#34;http://schemas.microsoft.com/expression/blend/2008&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:local=</span><span class="s">&#34;clr-namespace:MvvmToolkitExample&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:mc=</span><span class="s">&#34;http://schemas.openxmlformats.org/markup-compatibility/2006&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Title=</span><span class="s">&#34;MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Width=</span><span class="s">&#34;800&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Height=</span><span class="s">&#34;450&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">mc:Ignorable=</span><span class="s">&#34;d&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Grid&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;Grid.RowDefinitions&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="na">Height=</span><span class="s">&#34;auto&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="na">Height=</span><span class="s">&#34;auto&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/Grid.RowDefinitions&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;TextBlock</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;0&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">HorizontalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">VerticalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;32&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Text=</span><span class="s">&#34;{Binding Content}&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;TextBox</span>
</span></span><span class="line"><span class="cl">            <span class="na">x:Name=</span><span class="s">&#34;tb_msg&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Height=</span><span class="s">&#34;30&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Margin=</span><span class="s">&#34;10&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;20&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;Button</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;2&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Margin=</span><span class="s">&#34;10&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Padding=</span><span class="s">&#34;20&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">HorizontalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">VerticalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Command=</span><span class="s">&#34;{Binding ChangeContentWithParamCommand}&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">CommandParameter=</span><span class="s">&#34;{Binding ElementName=tb_msg, Path=Text}&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Content=</span><span class="s">&#34;带参命令绑定&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;20&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Grid&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Window&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ol>
<li>将 Button 控件的 Command 命令绑定在 ChangeContentWithParamCommand 上，当 Button 按钮按下时，会自动调用命令对应的方法 ChangeContentWithParam()。</li>
<li>将 TextBox 控件的 Text 属性，绑定在 Button 控件的 CommandParameter 属性上，作为命令参数用于调用对应方法。</li>
</ol>
<h4 id="界面后台代码-2">界面后台代码</h4>
<p>与 ObservableObject（可观测对象）- 界面后台代码 一致。</p>
<h4 id="viewmodel代码-2">ViewModel代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="c1">//ViewModel代码 MainWindowViewModel.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MainWindowViewModel</span> <span class="p">:</span> <span class="n">ObservableObject</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">int</span> <span class="n">times</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">    [ObservableProperty]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">string</span> <span class="n">content</span> <span class="p">=</span> <span class="s">&#34;通过MVVM方式，将字符串属性绑定到控件内容上&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">//当 Content 属性被修改后（赋值后），会调用该方法。</span>
</span></span><span class="line"><span class="cl">    <span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanged</span><span class="p">(</span><span class="kt">string?</span> <span class="n">oldValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">newValue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">times</span><span class="p">++;</span>
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="p">=</span> <span class="s">$&#34;{newValue} : { times }&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">    [RelayCommand]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">void</span> <span class="n">ChangeContentWithParam</span><span class="p">(</span><span class="kt">string</span> <span class="n">msg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Content</span> <span class="p">=</span> <span class="n">msg</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ol>
<li>声明无返回值 viod 的私有 private 方法 ChangeContentWithParam(string msg)。</li>
<li>生成器将使用方法名称并在末尾追加 “<strong>Command</strong>”，并且去除 “<strong>On</strong>” 前缀（如果存在）。</li>
<li>方法添加特性 [RelayCommand]，用于告诉编译器自动生成命令。</li>
</ol>
<h4 id="自动生成的代码-2">自动生成的代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="k">private</span> <span class="n">RelayCommand</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;?</span> <span class="n">changeContentWithParamCommand</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="n">IRelayCommand</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="n">ChangeContentWithParamCommand</span> <span class="p">=&gt;</span> <span class="n">changeContentWithParamCommand</span> <span class="p">??=</span> <span class="k">new</span> <span class="n">RelayCommand</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="n">ChangeContentWithParam</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="messager信使">Messager（信使）</h2>
<p>Messager 如名字所示，它是一个消息交换系统，其目的是实现一个松耦合的 MVVM 框架。让程序中不同类、界面或者模块之间可以简单、高效地进行数据交互。
其中核心的类就是 WeakReferenceMessenger 类。</p>
<h3 id="使用流程及工作模式">使用流程及工作模式</h3>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e4%bd%bf%e7%94%a8%e6%ad%a5%e9%aa%a4.png"
        data-srcset="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e4%bd%bf%e7%94%a8%e6%ad%a5%e9%aa%a4.png, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e4%bd%bf%e7%94%a8%e6%ad%a5%e9%aa%a4.png 1.5x, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e4%bd%bf%e7%94%a8%e6%ad%a5%e9%aa%a4.png 2x"
        data-sizes="auto"
        alt="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM框架-Messager使用步骤.png"
        title="使用步骤" /></p>
<p>Messager的使用共分为3步：</p>
<ol>
<li>注册一个消息类，这个类即作为消息主体本身，同时也作为在 Messager 中的 Token（标志）完成通信。</li>
<li>注册消息。在需要使用到该消息的地方使用 Messager 注册消息，当 Messager 收消息时会自动给调用该注册者的处理方法（Handler）。</li>
<li>发送消息。在程序的任何地方都可以通过 Messager 发送消息，Messager 组件会自动发送给注册者。</li>
</ol>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e5%b7%a5%e4%bd%9c%e6%a8%a1%e5%bc%8f.png"
        data-srcset="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e5%b7%a5%e4%bd%9c%e6%a8%a1%e5%bc%8f.png, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e5%b7%a5%e4%bd%9c%e6%a8%a1%e5%bc%8f.png 1.5x, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-Messager%e5%b7%a5%e4%bd%9c%e6%a8%a1%e5%bc%8f.png 2x"
        data-sizes="auto"
        alt="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM框架-Messager工作模式.png"
        title="工作模式" /></p>
<h3 id="weakreferencemessager">WeakReferenceMessager</h3>
<p>WeakReferenceMessenger 公开一个 Default 属性，该属性提供内置于包中的线程安全实现。一般情况下都会直接使用该对象直接进行通信。</p>
<h4 id="运行案例-3">运行案例</h4>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-WeakReferenceMessager.gif"
        data-srcset="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-WeakReferenceMessager.gif, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-WeakReferenceMessager.gif 1.5x, https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM%e6%a1%86%e6%9e%b6-WeakReferenceMessager.gif 2x"
        data-sizes="auto"
        alt="https://gitee.com/jacobcj/blog-pic/raw/master/blog/MVVM框架-WeakReferenceMessager.gif"
        title="WeakReferenceMessager" /></p>
<h4 id="xaml界面代码-3">XAML界面代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="c">&lt;!--前台界面代码 MainWindow.xaml--&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Window</span>
</span></span><span class="line"><span class="cl">    <span class="na">x:Class=</span><span class="s">&#34;MvvmToolkitExample.MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:x=</span><span class="s">&#34;http://schemas.microsoft.com/winfx/2006/xaml&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:d=</span><span class="s">&#34;http://schemas.microsoft.com/expression/blend/2008&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:local=</span><span class="s">&#34;clr-namespace:MvvmToolkitExample&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">xmlns:mc=</span><span class="s">&#34;http://schemas.openxmlformats.org/markup-compatibility/2006&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Title=</span><span class="s">&#34;MainWindow&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Width=</span><span class="s">&#34;800&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">Height=</span><span class="s">&#34;450&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">mc:Ignorable=</span><span class="s">&#34;d&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Grid&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;Grid.RowDefinitions&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="na">Height=</span><span class="s">&#34;auto&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;RowDefinition</span> <span class="na">Height=</span><span class="s">&#34;auto&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/Grid.RowDefinitions&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;TextBlock</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;0&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">HorizontalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">VerticalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;32&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Text=</span><span class="s">&#34;{Binding Content}&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;TextBox</span>
</span></span><span class="line"><span class="cl">            <span class="na">x:Name=</span><span class="s">&#34;tb_msg&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Height=</span><span class="s">&#34;30&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Margin=</span><span class="s">&#34;10&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;20&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;Button</span>
</span></span><span class="line"><span class="cl">            <span class="na">Grid.Row=</span><span class="s">&#34;2&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Margin=</span><span class="s">&#34;10&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Padding=</span><span class="s">&#34;20&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">HorizontalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">VerticalAlignment=</span><span class="s">&#34;Center&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Command=</span><span class="s">&#34;{Binding SendMessageCommand}&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">CommandParameter=</span><span class="s">&#34;{Binding ElementName=tb_msg, Path=Text}&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">Content=</span><span class="s">&#34;带参命令绑定——触发Messager&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">FontSize=</span><span class="s">&#34;20&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Grid&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Window&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>将 Button 控件的 Command 命令绑定在 SendMessageCommand 上，当 Button 按钮按下时，会自动调用命令对应的方法 SendMessage()。</p>
<h4 id="界面后台代码-3">界面后台代码</h4>
<p>与 ObservableObject（可观测对象）- 界面后台代码 一致。</p>
<h4 id="新建消息类">新建消息类</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="c1">//1. 新建消息</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">class</span> <span class="nc">ContentChangeMessage</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="n">ContentChangeMessage</span><span class="p">(</span><span class="kt">string</span> <span class="n">msg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Content</span> <span class="p">=</span> <span class="n">msg</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//消息主体内容，可以根据实际需求添加类的内容</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="kt">string</span> <span class="n">Content</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="viewmodel代码-3">ViewModel代码</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C#" data-lang="C#"><span class="line"><span class="cl"><span class="c1">//ViewModel代码 MainWindowViewModel.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MainWindowViewModel</span> <span class="p">:</span> <span class="n">ObservableObject</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="n">MainWindowViewModel</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//2. 注册消息</span>
</span></span><span class="line"><span class="cl">        <span class="n">WeakReferenceMessenger</span><span class="p">.</span><span class="n">Default</span><span class="p">.</span><span class="n">Register</span><span class="p">&lt;</span><span class="n">ContentChangeMessage</span><span class="p">&gt;(</span><span class="k">this</span><span class="p">,</span> <span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 处理程序</span>
</span></span><span class="line"><span class="cl">            <span class="n">Content</span> <span class="p">=</span> <span class="n">m</span><span class="p">.</span><span class="n">Content</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">int</span> <span class="n">times</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">    [ObservableProperty]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="kt">string</span> <span class="n">content</span> <span class="p">=</span> <span class="s">&#34;通过MVVM方式，将字符串属性绑定到控件内容上&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">//当 Content 属性被修改后（赋值后），会调用该方法。</span>
</span></span><span class="line"><span class="cl">    <span class="k">partial</span> <span class="k">void</span> <span class="n">OnContentChanged</span><span class="p">(</span><span class="kt">string?</span> <span class="n">oldValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">newValue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">times</span><span class="p">++;</span>
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="p">=</span> <span class="s">$&#34;{newValue} : { times }&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">    [RelayCommand]</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">void</span> <span class="n">SendMessage</span><span class="p">(</span><span class="kt">string</span> <span class="n">msg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//3. 发送消息</span>
</span></span><span class="line"><span class="cl">        <span class="n">WeakReferenceMessenger</span><span class="p">.</span><span class="n">Default</span><span class="p">.</span><span class="n">Send</span><span class="p">(</span><span class="k">new</span> <span class="n">ContentChangeMessage</span><span class="p">(</span><span class="n">msg</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ol>
<li>
<p>使用 WeakReferenceMessenger 的默认实现 Default 进行通信。</p>
</li>
<li>
<p>注册消息说明：WeakReferenceMessenger.Default.<strong>Register&lt; 消息类 &gt;( 接收者, 处理数据的委托 )</strong>;</p>
<p>接收消息的对象：一般为this</p>
<p>处理数据的委托：当接收到消息时会调用该委托，可以为 函数名 或者 Lambda表达式。</p>
<p>该委托包括 2 个参数：recipient（接收者）、handler（消息主体，message）</p>
</li>
<li>
<p>发送消息说明：WeakReferenceMessenger.Default.Send( 发送的消息主体对象 )</p>
<p>发送消息的对象：需要发送的 Message</p>
</li>
</ol>
<h2 id="参考资料">参考资料</h2>
<p>目前只是简单介绍了 MVVM Toolkit 最基本的使用。关于框架使用的更多内容，可以参考一下文章。</p>
<p><a href="https://github.com/JacobChenC/MvvmToolkitExample" target="_blank" rel="noopener noreffer ">本文案例程序-MvvmToolkitExample（github）</a></p>
<p><a href="https://www.cnblogs.com/dino623/p/building_MVVM_programs_using_MVVM_Toolkit.html" target="_blank" rel="noopener noreffer ">使用 MVVM Toolkit 构建 MVVM 程序</a></p>
<p><a href="https://www.cnblogs.com/dino623/p/mvvm-toolkit-source-generators.html" target="_blank" rel="noopener noreffer ">使用 MVVM Toolkit Source Generators</a></p>
<p><a href="https://learn.microsoft.com/zh-cn/dotnet/communitytoolkit/mvvm/" target="_blank" rel="noopener noreffer ">MVVM 工具包简介</a></p>
<p><a href="https://github.com/CommunityToolkit/MVVM-Samples" target="_blank" rel="noopener noreffer ">MVVM-Samples（github）</a></p>
</div><div class="post-footer" id="post-footer">
    <div class="post-info">
        <div class="post-info-line">
            <div class="post-info-mod">
                <span>更新于 2024-03-28</span>
            </div></div>
        <div class="post-info-line">
            <div class="post-info-md"><span>
                            <a class="link-to-markdown" href="/wpf_communitytoolkitmvvm/index.md" target="_blank">阅读原始文档</a>
                        </span></div>
            <div class="post-info-share">
                <span></span>
            </div>
        </div>
    </div>

    <div class="post-info-more">
        <section class="post-tags"><i class="fas fa-tags fa-fw" aria-hidden="true"></i>&nbsp;<a href="/tags/mvvm/">Mvvm</a>,&nbsp;<a href="/tags/wpf/">WPF</a></section>
        <section>
            <span><a href="javascript:void(0);" onclick="window.history.back();">返回</a></span>&nbsp;|&nbsp;<span><a href="/">主页</a></span>
        </section>
    </div>

    <div class="post-nav"><a href="/cia402_07ptpfunctionblock/" class="prev" rel="prev" title="CIA402从会到会不会——PTP功能块实现"><i class="fas fa-angle-left fa-fw" aria-hidden="true"></i>CIA402从会到会不会——PTP功能块实现</a></div>
</div>
</article></div>
            </main><footer class="footer">
        <div class="footer-container"><div class="footer-line">由 <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.115.4">Hugo</a> 强力驱动 | 主题 - <a href="https://github.com/dillonzq/LoveIt" target="_blank" rel="noopener noreffer" title="LoveIt 0.2.11"><i class="far fa-kiss-wink-heart fa-fw" aria-hidden="true"></i> LoveIt</a>
                </div><div class="footer-line" itemscope itemtype="http://schema.org/CreativeWork"><i class="far fa-copyright fa-fw" aria-hidden="true"></i><span itemprop="copyrightYear">2023 - 2024</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/" target="_blank">Jacob Chen</a></span>&nbsp;|&nbsp;<span class="license"><a rel="license external nofollow noopener noreffer" href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a></span></div>
        </div>
    </footer></div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="回到顶部">
                <i class="fas fa-arrow-up fa-fw" aria-hidden="true"></i>
            </a><a href="#" id="view-comments" class="fixed-button" title="查看评论">
                <i class="fas fa-comment fa-fw" aria-hidden="true"></i>
            </a>
        </div><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/autocomplete.js@0.38.1/dist/autocomplete.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lunr@2.3.9/lunr.min.js"></script><script type="text/javascript" src="/lib/lunr/lunr.stemmer.support.min.js"></script><script type="text/javascript" src="/lib/lunr/lunr.zh.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lazysizes@5.3.2/lazysizes.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js"></script><script type="text/javascript">window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":50},"comment":{},"search":{"highlightTag":"em","lunrIndexURL":"/index.json","lunrLanguageCode":"zh","lunrSegmentitURL":"/lib/lunr/lunr.segmentit.js","maxResultLength":10,"noResultsFound":"没有找到结果","snippetLength":30,"type":"lunr"}};</script><script type="text/javascript" src="/js/theme.min.js"></script></body>
</html>
